package com.ruoyi.common.utils.security;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import java.security.Key;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import javax.crypto.*;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.Security;
import java.util.Base64;
import java.util.Base64.Decoder;
import java.util.Base64.Encoder;

/**
 * 对称密钥密码算法工具类
 *
 * @author ruoyi
 */
public class CipherUtils
{

    private static final String MAC_NAME = "HmacSHA1";
    private static final String ENCODING = "utf-8";
    private static final String ALGORITHM = "DESede";


    /**
     * 生成随机秘钥
     *
     * @param keyBitSize 字节大小
     * @param algorithmName 算法名称
     * @return 创建密匙
     */
    public static Key generateNewKey(int keyBitSize, String algorithmName)
    {
        KeyGenerator kg;
        try
        {
            kg = KeyGenerator.getInstance(algorithmName);
        }
        catch (NoSuchAlgorithmException e)
        {
            String msg = "Unable to acquire " + algorithmName + " algorithm.  This is required to function.";
            throw new IllegalStateException(msg, e);
        }
        kg.init(keyBitSize);
        return kg.generateKey();
    }

    /**
     * 使用 HMAC-SHA1 签名方法对对encryptText进行签名
     *
     * @param encryptText 被签名的字符串
     * @param encryptKey  客户端身份密钥
     * @return 签名后的字符串
     */
    public static String signature(String encryptText, String encryptKey) {
        String result = null;
        try {
            Decoder de = Base64.getDecoder();
            SecretKey secretKey = new SecretKeySpec(de.decode(encryptKey.replaceAll(" ", "")), MAC_NAME);
            Mac mac = Mac.getInstance(MAC_NAME);
            mac.init(secretKey);
            byte[] text = encryptText.getBytes(ENCODING);
            byte[] tmp = mac.doFinal(text);
            Encoder en = Base64.getEncoder();
            result = en.encodeToString(tmp);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 3DES加密
     *
     * @param encryptText      被加密的字符串
     * @param encryptKey       客户端身份密钥
     * @param encryptionVector 加密向量
     * @param algorithm        加密模式CBC或者ECB
     * @return 加密后的字符串
     * @throws Exception 加密异常
     */
    public static String encrypt3DES(final String encryptText, final String encryptKey, final String encryptionVector,
                                     final String algorithm) throws Exception {
        Security.addProvider(new BouncyCastleProvider());
        SecretKey sKsecretKey = getKey(encryptKey);
        final Cipher cipher = Cipher.getInstance("DESede/" + algorithm + "/PKCS7Padding");
        if ("CBC".equals(algorithm.toUpperCase())) {
            final IvParameterSpec iv = new IvParameterSpec(encryptionVector.getBytes("UTF-8"));
            cipher.init(Cipher.ENCRYPT_MODE, sKsecretKey, iv);
        } else {
            cipher.init(Cipher.ENCRYPT_MODE, sKsecretKey);
        }
        final byte[] b = cipher.doFinal(encryptText.getBytes());
        final Encoder encoder = Base64.getEncoder();
        return encoder.encodeToString(b).replaceAll("\r", "").replaceAll("\n", "");
    }

    /**
     * 3DES解密
     *
     * @param decryptText      被加密的字符串
     * @param encryptKey       客户端身份密钥
     * @param encryptionVector 加密向量
     * @param algorithm        加密模式CBC或者ECB
     * @return 解密后的字符串
     * @throws Exception 解密异常
     */
    public static String decrypt3DES(final String decryptText, final String encryptKey, final String encryptionVector,
                                     final String algorithm) throws Exception {
        Security.addProvider(new BouncyCastleProvider());
        final Decoder decoder = Base64.getDecoder();
        final byte[] bytesrc = decoder.decode(decryptText);
        SecretKey sKsecretKey = getKey(encryptKey);
        final Cipher cipher = Cipher.getInstance("DESede/" + algorithm + "/PKCS7Padding");
        if ("CBC".equals(algorithm.toUpperCase())) {
            final IvParameterSpec iv = new IvParameterSpec(encryptionVector.getBytes("UTF-8"));
            cipher.init(Cipher.DECRYPT_MODE, sKsecretKey, iv);
        } else {
            cipher.init(Cipher.DECRYPT_MODE, sKsecretKey);
        }
        final byte[] retByte = cipher.doFinal(bytesrc);
        return new String(retByte);
    }

    /**
     * 使用DESede对secretKey进行加密
     *
     * @param secretKey 客户端身份密钥
     * @return SecretKey
     * @throws Exception 异常
     */
    public static SecretKey getKey(String secretKey) throws Exception {
        Decoder decoder = Base64.getDecoder();
        byte[] keyBytes = decoder.decode(secretKey);
        DESedeKeySpec dks = new DESedeKeySpec(keyBytes);
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
        SecretKey sKsecretKey = keyFactory.generateSecret(dks);
        return sKsecretKey;
    }

    /**
     * MD5加密
     *
     * @param target 待加密字符串
     * @return 加密后的MD5字符串
     * @throws Exception 异常
     */
    public static String encryptMd5(String target) throws Exception {
        if (target == null || target.trim().length() == 0) {
            return "";
        }
        MessageDigest md5Cipher = MessageDigest.getInstance("MD5");
        return byte2hex(md5Cipher.digest(target.getBytes(ENCODING)));
    }

    /**
     * SHA256加密
     *
     * @param target 需要加密的字符串
     * @return String
     * @throws Exception 异常
     */
    public static String encryptSha256(String target) throws Exception {
        if (target == null || target.trim().length() == 0) {
            return "";
        }
        MessageDigest sha256Cipher = MessageDigest.getInstance("SHA-256");
        sha256Cipher.update(target.getBytes(ENCODING));
        return byte2hex(sha256Cipher.digest());
    }

    // 二行制转十六进制
    private static String byte2hex(byte[] b) {
        StringBuilder hs = new StringBuilder();
        String stmp;
        for (int n = 0; b != null && n < b.length; n++) {
            stmp = Integer.toHexString(b[n] & 0XFF);
            if (stmp.length() == 1) {
                hs.append('0');
            }
            hs.append(stmp);
        }
        return hs.toString().toLowerCase();
    }

    /**
     * test
     *
     * @param args 参数
     * @throws Exception 异常
     */
    public static void main(String[] args) throws Exception {
        String encryptionVector = "PKCS5";
        String algorithm = "ECB";
        String requestRefIdKey = "requestRefId";
        String requestRefIdVal = "SJSREQ_2020052512121286860";
        String secretIdKey = "secretId";
        String secretIdVal = "10000";
        String encryptText = requestRefIdKey + "=" + requestRefIdVal + "&" + secretIdKey + "=" + secretIdVal;
        String encryptKey = "2020052512121286860FbnM2MXVRODEw";
        String signature = CipherUtils.signature(encryptText, encryptKey);
        System.out.println(signature);

        String requestMsg = "{\"param\":{\"mobile\":\"1234567890\",\"empowerNo\":\"20200525001\"}}";
        String request = encrypt3DES(requestMsg, encryptKey, encryptionVector, algorithm);
        System.out.println(request);

        String responseMsg = "P9ei/cUo2VrFT2LNGDgLhaORxMdRWdsL2ORIeEzju+c=";
        String response = decrypt3DES(responseMsg, encryptKey, encryptionVector, algorithm);
        System.out.println(response);

        System.out.println(encryptMd5("773373968_DDAPP"));
    }
}
